/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using MyPhotoIndex.Interfaces;
using MyPhotoIndex.Utilities.Types;
using MyPhotoIndex.Utilities;
using MyPhotoIndex.Interfaces.Plugins;
using System.Collections.ObjectModel;

namespace MyPhotoIndex.Plugins
{
    public class Manager
    {
        public static event EventHandler<PluginLoadEventArgs> PluginLoadEvent;

        private static List<Assembly> m_assemblies;
        private static List<IPlugin> m_plugins = new List<IPlugin>();
        private static string m_pluginsPath;

        public static void Init(string pluginsPath)
        {
            m_pluginsPath = pluginsPath;
            LoadAssemblies();
        }

        private static void LoadAssemblies()
        {
            m_assemblies = new List<Assembly>();

            string[] pluginFiles = Directory.GetFiles(m_pluginsPath, "*.dll", SearchOption.TopDirectoryOnly);
            foreach (string oneFile in pluginFiles)
            {
                Assembly pluginAssembly = Assembly.LoadFile(oneFile);
                m_assemblies.Add(pluginAssembly);
            }
        }

        public static void LoadPlugins(IApplicationContext applicationContext)
        {
            try
            {
                foreach (Assembly assembly in m_assemblies)
                {
                    try
                    {
                        LoadOneAssembly(assembly, applicationContext);
                    }
                    catch (Exception ex)
                    {
                        Logger.Log(ex);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Log(ex);
            }
        }

        public static void UnloadPlugins()
        {
            foreach (IPlugin plugin in m_plugins)
            {
                try
                {
                    plugin.Unload();
                }
                catch { }
            }
        }

        internal static void LoadOneAssembly(Assembly assembly, IApplicationContext applicationContext)
        {
            Type[] assemblyTypes = assembly.GetTypes();
            foreach (Type type in assemblyTypes)
            {
                try
                {
                    Type pluginInterface = type.GetInterface(typeof(IPlugin).Name);
                    if (pluginInterface != null)
                    {
                        IPlugin plugin = (IPlugin)assembly.CreateInstance(type.FullName);
                        if (plugin != null)
                        {
                            if (PluginLoadEvent != null)
                            {
                                PluginLoadEvent.Invoke(plugin, new PluginLoadEventArgs(plugin.Name, assembly.Location));
                            }

                            if (plugin.Load(applicationContext) == true)
                            {
                                m_plugins.Add(plugin);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    string msg = ex.Message;
                }
            }
        }

        public static ReadOnlyCollection<T> GetPlugins<T>()
        {
            List<T> list = new List<T>();

            Type pluginTtype = typeof(T);
            foreach (IPlugin plugin in m_plugins)
            {
                Type type = plugin.GetType().GetInterface(pluginTtype.Name);
                if (type != null)
                {
                    list.Add((T)plugin);
                }
            }

            if (list.Count == 0)
            {
                return null;
            }

            return list.AsReadOnly();
        }

        public static IPlugin GetPlugin(string typeName)
        {
            foreach (IPlugin plugin in m_plugins)
            {
                if (plugin.GetType().FullName.CompareTo(typeName) == 0)
                {
                    return plugin;
                }
            }

            return null;
        }

        public static Type GetType(string shortName)
        {
            foreach (Assembly assembly in m_assemblies)
            {
                Type foundType = TypeFinder.FindType(assembly, shortName);
                if (foundType != null)
                {
                    return foundType;
                }
            }

            return null;
        }
    }
}
